﻿using System;
using System.IO;
using System.Net;
using System.Xml;
using System.Text;
using System.Collections.Generic;

using VivendoByte.UploaderWSS.Properties;
using VivendoByte.UploaderWSS.net.vivendobyte.enjoy;
using VivendoByte.UploaderWSS.net.vivendobyte.enjoy1;

namespace VivendoByte.UploaderWSS
{
    public class ConnectorWSS
    {
        private string ListsWebService = "/_vti_bin/lists.asmx";
        private string SiteDataWebService = "/_vti_bin/sitedata.asmx";

        public string Server { get; set; }
        public string Username { get; set; }
        public string Password { get; set; }
        public string Domain { get; set; }
        public string WebSite { get; set; }
        public Dictionary<string, int> CacheFilesID { get; set; }
        public Dictionary<string, Guid> CacheWebID { get; set; }

        public ConnectorWSS()
        {
            this.Server = Settings.Default.ServerWS;
            this.Username = Settings.Default.Username;
            this.Password = Settings.Default.Password;
            this.Domain = Settings.Default.Domain;

            this.CacheFilesID = new Dictionary<string, int>();
            this.CacheWebID = new Dictionary<string, Guid>();
        }

        public Dictionary<string, string> GetLists()
        {
            Dictionary<string, string> result = new Dictionary<string, string>();
            
            Lists l = new Lists();
            l.Url = this.Server + "/" + this.WebSite + "/" + ListsWebService;
            l.Credentials = new NetworkCredential(this.Username, this.Password, this.Domain);
            XmlNode node = l.GetListCollection().FirstChild;

            do
            {
                result.Add(node.Attributes["Title"].Value, node.Attributes["ID"].Value);
                node = node.NextSibling;
            } while (node != null);

            return result;
        }

        public int GetLastID(string listName)
        {
            Lists l = new Lists();
            l.Url = this.Server + "/" + this.WebSite + "/" + ListsWebService;
            l.Credentials = new NetworkCredential(this.Username, this.Password, this.Domain);

            XmlDocument doc = new XmlDocument();
            XmlNode query = doc.CreateNode(XmlNodeType.Element, "Query", string.Empty);

            string xml = ResourceHelper.GetResourceContent("UploaderWSS.XML.GetLastIDQuery.xml");
            query.InnerXml = xml;

            string webId = this.GetWebID(Settings.Default.ServerWS + "/" + this.WebSite).ToString();
            XmlNode node = l.GetListItems(listName, null, query, null, "1", null, webId);

            node = node.FirstChild.NextSibling.FirstChild.NextSibling;

            string name = node.Attributes["ows_LinkFilename"].Value;
            int idFile = Int32.Parse(node.Attributes["ows_ID"].Value);

            this.CacheFilesID.Add(name, idFile);

            return idFile;
        }

        public int GetIDFromFilename(string listName, string folder, string fileName)
        {
            Lists l = new Lists();
            l.Url = this.Server + "/" + this.WebSite + "/" + ListsWebService;
            l.Credentials = new NetworkCredential(this.Username, this.Password, this.Domain);

            XmlDocument doc = new XmlDocument();
            XmlNode query = doc.CreateNode(XmlNodeType.Element, "Query", string.Empty);
            XmlNode options = doc.CreateNode(XmlNodeType.Element, "QueryOptions", string.Empty);

            if (!string.IsNullOrEmpty(folder))
                options.InnerXml = string.Format("<Folder>{0}</Folder>", folder);

            string xml = ResourceHelper.GetResourceContent("VivendoByte.UploaderWSS.XML.GetIDFromFilenameQuery.xml");
            query.InnerXml = string.Format(xml, fileName);

            string webId = this.GetWebID(this.Server + "/" + this.WebSite).ToString();
            XmlNode node = l.GetListItems(listName, null, query, null, "1", options, webId);

            node = node.FirstChild.NextSibling.FirstChild.NextSibling;

            if (node != null)
            {
                int idFile = Int32.Parse(node.Attributes["ows_ID"].Value);
                this.CacheFilesID.Add(fileName, idFile);
                return idFile;
            }
            else
                return 0;
        }

        public void UploadDocument(string localFilename, string remoteFilename)
        {
            FileStream strm = new FileStream(localFilename, FileMode.Open, FileAccess.Read);
            BinaryReader reader = new BinaryReader(strm);
            byte[] fileContents = reader.ReadBytes((int)strm.Length);
            reader.Close();
            strm.Close();

            string sRemoteFileURL = remoteFilename.Trim();
            sRemoteFileURL.Replace(@" ", @"%20");
            sRemoteFileURL.Replace(@"\", @"/");

            WebClient client = new WebClient();
            client.Credentials = new NetworkCredential(this.Username, this.Password, this.Domain);
            client.UploadData(sRemoteFileURL, "PUT", fileContents);
            client.Dispose();
        }

        public void UpdateDocumentMetadata(string listName, int idFile, Dictionary<string, string> values)
        {
            #region Building command using XML
            StringBuilder strBuilder = new StringBuilder();
            strBuilder.AppendLine("<Method ID='1' Cmd='Update'>");
            strBuilder.AppendFormat("<Field Name = 'ID'>{0}</Field>", idFile);

            Dictionary<string, string>.Enumerator enumerator = values.GetEnumerator();
            enumerator.MoveNext();

            do
            {
                strBuilder.AppendFormat("<Field Name = '{0}'>{1}</Field>", enumerator.Current.Key, enumerator.Current.Value);
            } while (enumerator.MoveNext());

            strBuilder.AppendLine("</Method>"); 
            #endregion

            XmlDocument doc = new XmlDocument();
            XmlElement elBatch = doc.CreateElement("Batch");
            elBatch.InnerXml = strBuilder.ToString();

            Lists l = new Lists();
            l.Url = this.Server + "/" + this.WebSite + "/" + ListsWebService;
            l.Credentials = new NetworkCredential(this.Username, this.Password, this.Domain);
            l.UpdateListItems(listName, elBatch);
        }

        public List<string> GetListDetails(string listName)
        {
            List<string> result = new List<string>();
            Lists l = new Lists();
            l.Url = this.Server + "/" + this.WebSite + "/" + ListsWebService;
            l.Credentials = new NetworkCredential(this.Username, this.Password, this.Domain);

            XmlNode node = l.GetList(listName).FirstChild;
            node = node.FirstChild;

            do
            {
                Console.WriteLine(node.Name + ", " + node.Attributes["ID"].Value);
                XmlNode attribute = node.Attributes.GetNamedItem("Hidden");

                if (attribute == null || attribute.Value.ToUpper().Equals("FALSE"))
                    result.Add(node.Attributes["Name"].Value);

                node = node.NextSibling;
            } while (node != null);

            return result;
        }

        public Guid GetWebID(string webPath)
        {
            if (this.CacheWebID.ContainsKey(webPath))
                return this.CacheWebID[webPath];

            SiteData siteDataWS = new SiteData();
            siteDataWS.Url = this.Server + "/" + this.WebSite + "/" + SiteDataWebService;
            siteDataWS.Credentials = new NetworkCredential(this.Username, this.Password, this.Domain);

            _sWebMetadata webMetaData;
            _sWebWithTime[] arrWebWithTime;
            _sListWithTime[] arrListWithTime;
            _sFPUrl[] arrUrls;

            string roles;
            string[] roleUsers;
            string[] roleGroups;

            siteDataWS.Url = webPath + "/_vti_bin/sitedata.asmx";

            uint i = siteDataWS.GetWeb(out webMetaData, out arrWebWithTime, out arrListWithTime, out arrUrls, out roles, out roleUsers, out roleGroups);

            Guid g = new Guid(webMetaData.WebID);

            this.CacheWebID.Add(webPath, g);
            return g;
        }
    }
}